﻿package component.formula.function;

import java.util.LinkedList;

import component.formula.exception.FormulaException;
import component.formula.operation.OperationFactory;
import component.formula.util.CalculateUtil;
import component.formula.util.StringUtil;


//简单的四则运算
public class Sum extends AbstractFunction {
	
	public static void main(String[] args) throws FormulaException {
		//System.out.println(parseFomular("1+3*(2+3)/(5)-(1-2)*2"));
		//System.out.println(parseFomular("3*(2+3)/(5-5)-(1-2)*2"));
		//System.out.println(parseFomular("(6548.30+0.00+41.00+320.00+477.00)*0.08"));
		
		//97215957397309696
		String exp = "(1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-0.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10";
		exp = "1+(2+3)";
		exp = "1+3*(2+3)/(5)-(1-2)*2";
		exp = "-1+3";
		exp = "3+(-1*2)";
		AbstractFunction fun = new Sum();
		System.out.println(fun.calculate(exp));
		System.out.println(1+3*(2+3)/(5)-(1-2)*2);
		//System.out.println((1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-0.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10*(1-((1-3.9)*(45-5))/5)*10);
	}
	
	private static String t = "";
	
	//使用链表算法计算
	public Object calculate(String expression) throws FormulaException {
		// TODO Auto-generated method stub
		if(StringUtil.isNull(expression)){
			throw new FormulaException("四则运算的表达式不能为空");
		}
		if(CalculateUtil.isNumberAndPoint(expression)){
			return expression;
		}
		if(expression.charAt(0)=='-') expression = "0" + expression;
		LinkedList oper = new LinkedList();
		oper.addFirst(new Token('#'));
		LinkedList num = new LinkedList();
		for (int i = 0; i < expression.length(); i++) {
			char c = expression.charAt(i);
			if (c == '(') {
				if (!t.equals("")) {
					num.addFirst(t);
					t = "";
				}
				oper.addFirst(new Token('('));
			}
			else if (c == ')') {
				if (!t.equals("")) {
					num.addFirst(t);
					t = "";
				}
				while (true) {
					Token cur = (Token)oper.removeFirst();
					if (cur.c == '(')
						break;
					calculate(oper,num,cur);
				}
			}
			else if (c == '+') {
				calculate(oper,num,'+');
			}
			else if (c == '-') {
				char preChar = expression.charAt(i-1);
				if(CalculateUtil.isOperatorOrBracket(preChar)){//此时"-"是负号,而不是减号
					t += c;
				}else{
					calculate(oper,num,'-');
				}
			}
			else if (c == '*') {
				calculate(oper,num,'*');
			}
			else if (c == '/') {
				calculate(oper,num,'/');
			}
			else if ( (c >= '0' && c <= '9') || c == '.'){
				t += c;
			}
		}
		if (!t.equals(""))
			num.addFirst(t);
		while (oper.size() > 1) {
			Token cur = (Token)oper.removeFirst();
			calculate(oper,num,cur);
		}
		t = "";
		return num.getFirst();
	}
	
	
	
	private static void calculate(LinkedList oper,LinkedList num,char operator) throws FormulaException{
		if (!t.equals("")) {
			num.addFirst(t);
			t = "";
		}
		Token tnew = new Token(operator);
		while (true) {
			Token cur = (Token)oper.removeFirst();
			if (tnew.level > cur.level) {
				oper.addFirst(cur);
				oper.addFirst(tnew);
				break;
			} else {
				calculate(oper,num,cur);
			}
		}
	}
	
	private static void calculate(LinkedList oper,LinkedList num,Token cur) throws FormulaException{
		String d2 = (String)num.removeFirst();
		String d1 = (String)num.removeFirst();
		
		Object value = OperationFactory.getOperation(String.valueOf(cur.c)).calculate(d1, d2);
		num.addFirst(String.valueOf(value));
	}

}

class Token {
	public char c;
	public int level;// 运算优先级 ：(:0 , +:1 , -:1 , *:2 , /:2 , ):3
	
	public Token(char c) {
		this.c = c;
		if(c=='('){this.level=0;}
		else if(c=='+' || c=='-'){this.level=1;}
		else if(c=='*' || c=='/'){this.level=2;}
		else if(c==')'){this.level=3;}
		else{//#
			this.level=-1;
		}
	}
}
